home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / System / Swatch / Development / swatch 1.7 / display.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-12  |  21.7 KB  |  986 lines  |  [TEXT/KAHL]

  1. /**
  2.  
  3.     display.c
  4.     Copyright (c) 1990-1992, joe holt
  5.  
  6.  **/
  7.  
  8.  
  9. /**-----------------------------------------------------------------------------
  10.  **
  11.  **    Headers
  12.  **
  13.  **/
  14.  
  15. #ifndef __ctypes__
  16. #include "ctypes.h"
  17. #endif
  18. #ifndef __display__
  19. #include "display.h"
  20. #endif
  21. #ifndef __content__
  22. #include "content.h"
  23. #endif
  24. #ifndef __heap__
  25. #include "heap.h"
  26. #endif
  27. #ifndef __heap_list__
  28. #include "heap_list.h"
  29. #endif
  30. #ifndef __prefs__
  31. #include "prefs.h"
  32. #endif
  33. #ifndef __pstring__
  34. #include "pstring.h"
  35. #endif
  36. #ifndef __resources__
  37. #include "resources.h"
  38. #endif
  39. #ifndef __swatch__
  40. #include "swatch.h"
  41. #endif
  42. #ifndef __window__
  43. #include "window.h"
  44. #endif
  45.  
  46.  
  47. /**-----------------------------------------------------------------------------
  48.  **
  49.  ** Private Macros
  50.  **
  51.  **/
  52.  
  53. /**-----------------------------------------------------------------------------
  54.  **
  55.  ** Private Constants
  56.  **
  57.  **/
  58.  
  59. #define MIN_DEPTH_FOR_COLOR                4
  60. #define COLOR8                            0
  61. #define COLOR4                            1
  62. #define GRAY8                            2
  63. #define GRAY4                            3
  64.  
  65. #define MBOX_HEAP_ADDRESS                1
  66. #define MBOX_ADDRESS                    2
  67.  
  68. #define MIN_COLUMN_LEFT            3
  69.  
  70. #define NAME_TOP_DELTA            2
  71. #define SIZE_TOP_DELTA            2
  72. #define FREE_TOP_DELTA            2
  73. #define ISLANDS_TOP_DELTA        2
  74. #define TEXT_HEIGHT                12
  75.  
  76.  
  77. /**-----------------------------------------------------------------------------
  78.  **
  79.  ** Private Variables
  80.  **
  81.  **/
  82.  
  83. static unsigned char mbox_text[256] = {0};
  84.  
  85. static CTabHandle cluts[4];
  86. static CTabHandle current_clut;
  87. static int16 clut_index;
  88. static Handle patterns, marching_ants;    /* PAT# resource */
  89. static Boolean color_is_dead = false;
  90.  
  91.  
  92. typedef void (*display_proc_t)( Heap_info_t *hi, column_t *col, Boolean force );
  93.  
  94.  
  95. /**-----------------------------------------------------------------------------
  96.  **
  97.  ** Private Functions
  98.  **
  99.  **/
  100.  
  101. static void display_updating( Heap_info_t *hi, column_t *col, Boolean force );
  102. static void display_name( Heap_info_t *hi, column_t *col, Boolean force );
  103. static void display_current_size( Heap_info_t *hi, column_t *col, Boolean force );
  104. static void display_current_free( Heap_info_t *hi, column_t *col, Boolean force );
  105. static void display_current_islands( Heap_info_t *hi, column_t *col, Boolean force );
  106. static void display_heap( Heap_info_t *hi, column_t *col, Boolean force );
  107. static void display_selection( struct _t_Heap_info *hi, column_t *col, Boolean force );
  108.  
  109. static void add_commas( unsigned char *num );
  110. static void draw_mbox( Rect *r );
  111.  
  112.  
  113. static cell_t cells[] = {
  114.     { colUpdating,    (ProcPtr) display_updating,            9, 5,        0 },
  115.     { colName,        (ProcPtr) display_name,                70, 5,         0 },
  116.     { colSize,        (ProcPtr) display_current_size,        70, 5,         Heap_Size_STR_x },
  117.     { colFree,        (ProcPtr) display_current_free,        70, 5,         Heap_Free_STR_x },
  118.     { colIslands,    (ProcPtr) display_current_islands,    50, 10,        Heap_Islands_STR_x },
  119.     { colHeap,        (ProcPtr) display_heap,                16384, 0,    0 }
  120. };
  121.  
  122.  
  123. /*******************************************************************************
  124.  **
  125.  **    Public Variables
  126.  **
  127.  **/
  128.  
  129. Boolean Use_color;
  130. int16 Max_columns = 5;  // number of elements below - 1
  131. int16 Column_types[6] = { colUpdating, colName, colSize, colFree, colIslands, colHeap };
  132.  
  133.  
  134. /*******************************************************************************
  135.  **
  136.  **    Public Functions
  137.  **
  138.  **/
  139.  
  140. void Display_init( void )
  141. {
  142.     Handle h;
  143.  
  144.     patterns = GetResource( 'PAT#', BLACK_WHITE_PAT_ );
  145.     if ( !patterns ) Bail( OUT_OF_MEMORY_ALRT );
  146.  
  147.     marching_ants = GetResource( 'PAT#', MARCHING_ANTS_PAT_ );
  148.     if ( !marching_ants ) Bail( OUT_OF_MEMORY_ALRT );
  149.  
  150.     Window_set_mbox( draw_mbox );
  151.  
  152.  
  153.     h = GetResource( 'STUF', 1 );
  154.     if ( h ) {
  155.  
  156.         int16 *p;
  157.         int i;
  158.  
  159.         HLock( h );
  160.  
  161.         p = (int16 *) *h;
  162.         Max_columns = *p++;
  163.         for ( i = 0; i <= Max_columns; ++i ) Column_types[i] = *p++;
  164.  
  165.         HUnlock( h );
  166.         ReleaseResource( h );
  167.  
  168.     }
  169.  
  170. }
  171.  
  172.  
  173. void Display_update_row_tops( void )
  174. {
  175.     Heap_info_handle_t h;
  176.     Heap_info_t *hi;
  177.     int16 top;
  178.  
  179.     top = BORDER_BOTTOM - GetCtlValue( vert_scroll ) * CELL_HEIGHT;
  180.     h = nil;
  181.     while ( h = l_next( heaps, h ) ) {
  182.         Heap_info_t *hi = l_access( h );
  183.         hi->row.top = top;
  184.         hi->row.bottom = top + CELL_HEIGHT;
  185.         top += CELL_HEIGHT;
  186.         l_release( h );
  187.     }
  188. }
  189.  
  190.  
  191. void Display_new_row_arrangement( int16 max_columns, int16 *column_types )
  192. {
  193.     Heap_info_handle_t h;
  194.     int i;
  195.  
  196.     assert( max_columns >= 2, "\p Display_new_row_arrangement(): too few columns" );
  197.     Max_columns = max_columns;
  198.  
  199.     for ( i = 0; i <= max_columns; ++i ) Column_types[i] = *column_types++;
  200.  
  201.     h = nil;
  202.     while ( (h = l_next( heaps, h )) ) Display_new_row( h );
  203.  
  204. }
  205.  
  206.  
  207. void Display_new_row( Heap_info_handle_t h )
  208. {
  209.     Heap_info_t *hi;
  210.     int i, j;
  211.     int16 left;
  212.     column_t *col;
  213.  
  214.     hi = l_access( h );
  215.  
  216.     hi->row.max_columns = Max_columns;
  217.  
  218.     left = MIN_COLUMN_LEFT;
  219.     for ( i = 0, col = &hi->row.column[0]; i <= hi->row.max_columns; ++i, ++col ) {
  220.  
  221.         for ( j = MAX_COLUMNS - 1; j >= 0; --j )
  222.             if ( cells[j].type == Column_types[i] ) break;
  223.         assert ( j >= 0, "\p Display_build_row(): couldn't find column type" );
  224.  
  225.         col->cell = &cells[j];
  226.         col->left = left;
  227.         col->right = left + col->cell->width;
  228.         left = col->right + col->cell->space;
  229.  
  230.     }
  231.  
  232.     col = Display_find_column( hi, colHeap );
  233.     assert( col != &hi->row.column[0], "\p Display_new_row(): can't handle heap as first column" );
  234.     MBox_right = (col->left + (col-1)->right) / 2 - 1;
  235.  
  236.     hi->last_islands = -1;
  237.  
  238.     l_release( h );
  239. }
  240.  
  241.  
  242. int16 Display_row( int16 update, Heap_info_handle_t h )
  243. {
  244.     Boolean force;
  245.     Heap_info_t *hi;
  246.     column_t *col;
  247.     int j;
  248.     Rect clip, contents;
  249.     int16 bottom;
  250.  
  251.     if ( !update ) return;
  252.  
  253.     force = (update & FORCE_UPDATE) != 0;
  254.  
  255.     Heap_list_update_one( h );
  256.     hi = l_access( h );
  257.  
  258.     contents.left = 0;
  259.     contents.top = BORDER_BOTTOM;
  260.     contents.right = App_window->portRect.right - 15;
  261.     contents.bottom = App_window->portRect.bottom - 15;
  262.     SetRect( &clip, 0, hi->row.top, 16384, hi->row.bottom );
  263.     SectRect( &clip, &contents, &clip );
  264.  
  265.     if ( !EmptyRect( &clip ) ) {
  266.  
  267.         if ( hi->updating ) {
  268.  
  269.             hi->last_updating = true;
  270.  
  271.             ClipRect( &clip );
  272.  
  273.             for ( j = hi->row.max_columns, col = &hi->row.column[j]; j >= 0; --j, --col ) {
  274.         
  275.                 if ( col->cell->type & update )
  276.                     ((display_proc_t)col->cell->draw)( hi, col, force );
  277.         
  278.             }
  279.             if ( update & UPDATE_SELECTION ) display_selection( hi, nil, force );
  280.  
  281.             Window_clip_with_controls();
  282.  
  283.         }
  284.  
  285.         else {
  286.  
  287.             if ( colName & update ) {
  288.  
  289.                 ClipRect( &clip );
  290.                 col = Display_find_column( hi, colName );
  291.                 ((display_proc_t)col->cell->draw)( hi, col, force );
  292.                 Window_clip_with_controls();
  293.  
  294.             }
  295.  
  296.             if ( hi->last_updating ) {
  297.  
  298.                 int16 right = clip.right;
  299.     
  300.                 hi->last_updating = false;  // = hi->updating
  301.  
  302.                 col = Display_find_column( hi, colUpdating );
  303.                 clip.left = col->left;
  304.                 clip.right = col->right;
  305.                 EraseRect( &clip );
  306.  
  307.                 col = Display_find_column( hi, colName );
  308.                 clip.left = col->right;
  309.                 clip.right = MBox_right;
  310.                 EraseRect( &clip );
  311.  
  312.                 clip.left = MBox_right + 1;
  313.                 clip.right = right;
  314.                 EraseRect( &clip );
  315.  
  316.             }
  317.  
  318.         }
  319.  
  320.  
  321.     }
  322.     bottom = hi->row.bottom;
  323.  
  324.  
  325.     l_release( h );
  326.  
  327.     return bottom;
  328. }
  329.  
  330.  
  331. void Display_lines( int16 update, int16 line_start, int16 line_end )
  332. {
  333.     Heap_info_handle_t h;
  334.     int16 bottom;
  335.     int i;
  336.  
  337.     if ( !update ) return;
  338.  
  339.     if ( line_start == DISPLAY_ALL ) {
  340.         Display_header( update );
  341.         line_start = 0;
  342.         line_end = Content_rows() - 1;
  343.         if ( Content_partial_row() )
  344.             ++line_end;
  345.     }
  346.  
  347.     line_start += GetCtlValue( vert_scroll );
  348.     line_end += GetCtlValue( vert_scroll );
  349.  
  350.     h = nil;
  351.     for ( i = line_start; i; --i ) h = l_next( heaps, h );
  352.  
  353.  
  354.     bottom = BORDER_BOTTOM + 1;
  355.     for ( i = line_start; (h = l_next( heaps, h )) && i <= line_end; ++i )
  356.         bottom = Display_row( update, h );
  357.  
  358.     
  359.     if ( update & UPDATE_BOTTOM ) {
  360.         Rect erase;
  361.  
  362.         erase.bottom = App_window->portRect.bottom - 15;
  363.  
  364.         if ( bottom < erase.bottom ) {
  365.  
  366.             erase.top = bottom;
  367.             erase.left = 0;
  368.             erase.right = MBox_right;
  369.             EraseRect( &erase );
  370.             erase.left = MBox_right + 1;
  371.             erase.right = App_window->portRect.right - 15;
  372.             EraseRect( &erase );
  373.  
  374.         }
  375.     }
  376. }
  377.  
  378.  
  379. void Display_header( int16 update )
  380. {
  381.     unsigned char header_text1[50], header_text2[50];
  382.     unsigned char num[30];
  383.     uns32 pixels_visible;
  384.     Rect erase;
  385.     Point pen;
  386.     int16 header_text2_pos;
  387.     unsigned char *str;
  388.     int16 width;
  389.     int i, x;
  390.     Heap_info_handle_t h;
  391.     Heap_info_t *hi;
  392.  
  393.      h = l_next( heaps, nil );
  394.      hi = l_access( h );
  395.  
  396.     if ( update & UPDATE_HEADER ) {
  397.  
  398.         erase.left = 0;
  399.         erase.right = MBox_right;
  400.         erase.top = BORDER_TOP;
  401.         erase.bottom = BORDER_BOTTOM - 1;
  402.         EraseRect( &erase );
  403.     
  404.         Set_fore_color( HEADER_COLOR );
  405.     
  406.         for ( i = hi->row.max_columns; i >= 0; --i ) {
  407.     
  408.             x = hi->row.column[i].cell->name;
  409.             if ( x ) {
  410.     
  411.                 str = pstr( x );
  412.                 width = StringWidth( str );
  413.     
  414.                 MoveTo( hi->row.column[i].right - width, CELL_HEIGHT - 2 );
  415.                 DrawString( str );
  416.     
  417.             }
  418.     
  419.         }
  420.     }
  421.  
  422.  
  423.     if ( update & UPDATE_HEAP_SCALE ) {
  424.  
  425.         erase.left = MBox_right;
  426.         erase.right = 16384;
  427.         erase.top = BORDER_TOP;
  428.         erase.bottom = BORDER_BOTTOM - 1;
  429.         EraseRect( &erase );
  430.  
  431.         pstrcopy( pstr(Heap_pixel_1_STR_x), header_text1 );
  432.         pnumcopy( Prefs.heap_scale, num );
  433.         add_commas( num );
  434.         pstrappend( num, header_text1 );
  435.         pstrappend( pstr(Heap_pixel_bytes_STR_x), header_text1 );
  436.     
  437.         pixels_visible = App_window->portRect.right - 15 -
  438.                 Display_find_column( hi, colHeap )->left;
  439.         pnumcopy( pixels_visible * Prefs.heap_scale, header_text2 );
  440.         add_commas( header_text2 );
  441.         pstrappend( pstr(Heap_pixel_visible_STR_x), header_text2 );
  442.     
  443.         Set_fore_color_or_pattern( HEADER_BORDER_COLOR );
  444.         MoveTo( 0, BORDER_BOTTOM - 1 );
  445.         Line( 16384, 0 );
  446.     
  447.         Set_fore_color( HEADER_COLOR );
  448.         MoveTo( MBox_right + 10, BORDER_BOTTOM - 2 );
  449.         DrawString( header_text1 );
  450.         GetPen( &pen );
  451.         pen.h += 5;
  452.         header_text2_pos = App_window->portRect.right - 15 -
  453.                 StringWidth( header_text2 );
  454.         MoveTo( header_text2_pos < pen.h ? pen.h : header_text2_pos, CELL_HEIGHT - 2 );
  455.         DrawString( header_text2 );
  456.  
  457.     }
  458.  
  459.     Set_fore_color( BLACK_COLOR );
  460.  
  461.     l_release( h );
  462. }
  463.  
  464.  
  465. #define CHECK_LEFT        (BOX_FIELD_LEFT + 2)
  466. #define CHECK_BOTTOM    (hi->row.top + CELL_HEIGHT - 5)
  467.  
  468. static void display_updating( Heap_info_t *hi, column_t *col, Boolean force )
  469. {
  470.     if ( force ) {
  471.         MoveTo( col->left, CHECK_BOTTOM - 2 );
  472.         LineTo( col->left + 2, CHECK_BOTTOM  );
  473.         LineTo( col->left + 7, CHECK_BOTTOM - 5 );
  474.     }
  475. }
  476.  
  477.  
  478. static void display_name( Heap_info_t *hi, column_t *col, Boolean force )
  479. {
  480.     unsigned char name[32];
  481.     int16 len, length_pixel_limit;
  482.     unsigned char *p;
  483.     Rect field;
  484.  
  485.     if ( force ) {
  486.         field.left = col->left;
  487.         field.right = col->right;
  488.         field.top = hi->row.top;
  489.         field.bottom = hi->row.bottom;
  490.     
  491.         length_pixel_limit = col->right - col->left - 5;
  492.         pstrcopy( hi->appname, name );
  493.         if ( (len = StringWidth(name)) > length_pixel_limit ) {
  494.             p = name + *name;
  495.             do {
  496.                 len -= CharWidth( *p );
  497.                 --p;
  498.                 --*name;
  499.             } while ( len > length_pixel_limit );
  500.             *p = '…';
  501.             len += CharWidth( '…' );
  502.         }
  503.         EraseRect( &field );
  504.     
  505.         MoveTo( field.left + 1, hi->row.top + NAME_TOP_DELTA + TEXT_HEIGHT - 2 );
  506.         Set_fore_color( NAME_COLOR );
  507.         DrawString( name );
  508.         Set_fore_color( BLACK_COLOR );
  509.     }
  510. }
  511.  
  512.  
  513. static void display_current_size( Heap_info_t *hi, column_t *col, Boolean force )
  514. {
  515.     unsigned char num[20];
  516.     Rect field;
  517.     int left;
  518.  
  519.     if ( hi->current_size != hi->last_size || force ) {
  520.  
  521.         hi->last_size = hi->current_size;
  522.  
  523.         field.left = col->left;
  524.         field.right = col->right;
  525.         field.top = hi->row.top + SIZE_TOP_DELTA;
  526.         field.bottom = field.top + TEXT_HEIGHT;
  527.     
  528.         pnumcopy( hi->current_size, num );
  529.         add_commas( num );
  530.  
  531.         EraseRect( &field );
  532.  
  533.         field.left = field.right - StringWidth( (StringPtr)num );
  534.  
  535.         MoveTo( field.left, field.bottom - 2 );
  536.         Set_fore_color( SIZE_COLOR );
  537.         DrawString( num );
  538.         Set_fore_color( BLACK_COLOR );
  539.  
  540.     }
  541. }
  542.  
  543.  
  544. static void display_current_free( Heap_info_t *hi, column_t *col, Boolean force )
  545. {
  546.     unsigned char num[20];
  547.     Rect field;
  548.  
  549.     if ( hi->current_free != hi->last_free || force ) {
  550.  
  551.         hi->last_free = hi->current_free;
  552.  
  553.         field.left = col->left;
  554.         field.right = col->right;
  555.         field.top = hi->row.top + FREE_TOP_DELTA;
  556.         field.bottom = field.top + TEXT_HEIGHT;
  557.  
  558.         pnumcopy( hi->current_free, num );
  559.         add_commas( num );
  560.  
  561.         EraseRect( &field );
  562.  
  563.         field.left = field.right - StringWidth( (StringPtr)num );
  564.  
  565.         MoveTo( field.left, field.bottom - 2 );
  566.         Set_fore_color( FREE_COLOR );
  567.         DrawString( num );
  568.         Set_fore_color( BLACK_COLOR );
  569.  
  570.     }
  571. }
  572.  
  573.  
  574. static void display_current_islands( Heap_info_t *hi, column_t *col, Boolean force )
  575. {
  576.     unsigned char num[20];
  577.     Rect field;
  578.  
  579.     if ( hi->current_islands != hi->last_islands || force ) {
  580.  
  581.         hi->last_islands = hi->current_islands;
  582.  
  583.         field.left = col->left;
  584.         field.right = col->right;
  585.         field.top = hi->row.top + ISLANDS_TOP_DELTA;
  586.         field.bottom = field.top + TEXT_HEIGHT;
  587.     
  588.         pnumcopy( hi->current_islands, num );
  589.         add_commas( num );
  590.  
  591.         EraseRect( &field );
  592.  
  593.         field.left = field.right - StringWidth( (StringPtr)num );
  594.  
  595.         MoveTo( field.left, field.bottom - 2 );
  596.         Set_fore_color( HEADER_COLOR );
  597.         DrawString( num );
  598.         Set_fore_color( BLACK_COLOR );
  599.  
  600.     }
  601. }
  602.  
  603.  
  604. static void display_heap( Heap_info_t *hi, column_t *col, Boolean force )
  605. {
  606.     int32 *p, *q;
  607.     int16 i, right_pixel_limit;
  608.     int32 right, offset;
  609.     unsigned char run;
  610.     Boolean update;
  611.     Rect field;
  612.  
  613.     field.left = col->left - 1;
  614.     field.right = App_window->portRect.right - 15;
  615.     field.top = hi->row.top + 2;
  616.     field.bottom = hi->row.bottom - 2;
  617.  
  618.     right_pixel_limit = field.right;
  619.  
  620.  
  621.     update = force;
  622.  
  623.     if ( hi->current_heap_ok != hi->last_heap_ok ) {
  624.         hi->last_heap_ok = hi->current_heap_ok;
  625.         update = true;
  626.     }
  627.  
  628.     if ( hi->current_heap_transitions != hi->last_heap_transitions ) {
  629.         hi->last_heap_transitions = hi->current_heap_transitions;
  630.         update = true;
  631.     }
  632.  
  633.     for ( i = hi->current_heap_transitions, p = hi->current_heap, q = hi->last_heap; i; --i ) {
  634.         if ( !update && *p != *q )
  635.             update = true;
  636.         *q++ = *p++;
  637.     }
  638.  
  639.     hi->current_heap_offset_pixels = Content_heap_offset_pixels();
  640.     if ( hi->current_heap_offset_pixels != hi->last_heap_offset_pixels ) {
  641.         hi->last_heap_offset_pixels = hi->current_heap_offset_pixels;
  642.         update = true;
  643.     }
  644.  
  645.     if ( !update ) return;
  646.  
  647.  
  648.     if ( !hi->current_heap_ok ) {
  649.         EraseRect( &field );
  650.         MoveTo( col->left, field.bottom - 2 );
  651.         TextFace( bold );
  652.         DrawString( pstr(Heap_damaged_STR_x) );
  653.         TextFace( 0 );
  654.         return;
  655.     }
  656.  
  657.     offset = 0;
  658.     i = hi->current_heap_transitions;
  659.     p = hi->current_heap;
  660.     do {
  661.         offset += *p++ & 0x00FFFFFF;
  662.     } while ( offset < hi->current_heap_offset_pixels && --i );
  663.     if ( !i ) {
  664.         EraseRect( &field );
  665.         return;
  666.     }
  667.  
  668.     Set_fore_color_or_pattern( ( !hi->current_heap_offset_pixels ?
  669.             HEAP_BORDER_COLOR : BACK_COLOR ) );
  670.     MoveTo( field.left, field.top );
  671.     Line( 0, CELL_HEIGHT - 5 );
  672.  
  673.     InsetRect( &field, 1, 1 );
  674.     field.left = col->left;
  675.     offset -= hi->current_heap_offset_pixels;
  676.     run = *(unsigned char *) (p - 1);
  677.     for ( ;; ) {
  678.  
  679.         switch ( run ) {
  680.         case HEAP_FREE_RUN:
  681.             Set_fore_color_or_pattern( HEAP_FREE_COLOR );
  682.             break;
  683.         case HEAP_LOCKED_RUN:
  684.             Set_fore_color_or_pattern( HEAP_LOCKED_COLOR );
  685.             break;
  686.         case HEAP_UNLOCKED_RUN:
  687.             Set_fore_color_or_pattern( HEAP_UNLOCKED_COLOR );
  688.             break;
  689.         case HEAP_PURGEABLE_RUN:
  690.             Set_fore_color_or_pattern( HEAP_PURGEABLE_COLOR );
  691.             break;
  692.         default:
  693.             Set_fore_color_or_pattern( BLACK_COLOR );
  694.             break;
  695.         }
  696.  
  697.         if ( offset < 16384 ) {
  698.             field.right = field.left + offset;
  699.             if ( field.right > right_pixel_limit ) field.right = right_pixel_limit;
  700.         }
  701.         else field.right = right_pixel_limit;
  702.  
  703.         PaintRect( &field );
  704.         field.left = field.right;
  705.  
  706.         if ( field.left >= right_pixel_limit || !--i ) break;
  707.  
  708.         run = *(unsigned char *) p;
  709.         offset = *p++ & 0x00FFFFFF;
  710.     }
  711.  
  712.     InsetRect( &field, 0, -1 );
  713.     if ( field.right < right_pixel_limit ) {
  714.         Set_fore_color_or_pattern( HEAP_BORDER_COLOR );
  715.         MoveTo( field.right, field.top );
  716.         Line( 0, CELL_HEIGHT - 5 );
  717.     }
  718.     Set_fore_color_or_pattern( BLACK_COLOR );
  719.  
  720.     MoveTo( col->left, field.top );
  721.     LineTo( field.right, field.top );
  722.     MoveTo( col->left, field.bottom - 1 );
  723.     LineTo( field.right, field.bottom - 1 );
  724.  
  725.     ++field.left;
  726.     if ( hi->last_heap_x != field.left || force ) {
  727.         if ( hi->last_heap_x > field.left || force ) {
  728.             field.right = right_pixel_limit;
  729.             if ( field.left < field.right )
  730.                 EraseRect( &field );
  731.         }
  732.         hi->last_heap_x = field.left;
  733.     }
  734. }
  735.  
  736.  
  737. static void display_selection( Heap_info_t *hi, column_t *col, Boolean force )
  738. {
  739.     Boolean update_heap;
  740.  
  741.     if ( !col ) col = Display_find_column( hi, colHeap );
  742.  
  743.     update_heap = false;
  744.  
  745.     if ( hi->has_selection != hi->last_has_selection ) {
  746.         hi->last_has_selection = hi->has_selection;
  747.         update_heap = true;
  748.     }
  749.  
  750.     if ( (hi->current_selection.physical_start != hi->last_selection.physical_start) ||
  751.          (hi->current_selection.physical_end   != hi->last_selection.physical_end) ) {
  752.         hi->last_selection = hi->current_selection;
  753.         update_heap = true;
  754.     }
  755.  
  756.     if ( update_heap ) display_heap( hi, col, true );
  757.  
  758.  
  759.     if ( hi->has_selection ) {
  760.         int32 pixel_left, pixel_right, right_pixel_limit;
  761.         int16 t, b, phase_offset_top, phase_offset_bottom;
  762.         PenState save_pen;
  763.         Boolean left_off, right_off;
  764.  
  765.         pixel_left = Content_address_to_pixel( hi, hi->current_selection.physical_start );
  766.         pixel_right = Content_address_to_pixel( hi, hi->current_selection.physical_end );
  767.         right_pixel_limit = App_window->portRect.right - 15;
  768.  
  769.         if ( !((pixel_left > right_pixel_limit) || (pixel_right < col->left)) ) {
  770.  
  771.             left_off = pixel_left < col->left;
  772.             right_off = pixel_right > right_pixel_limit;
  773.  
  774.             t = hi->row.top + 3;
  775.             b = hi->row.bottom - 4;
  776.  
  777.             GetPenState( &save_pen );
  778.             PenMode( patCopy );
  779.             if ( Swatch_in_foreground() ) {
  780.                 phase_offset_top = hi->selection_phase * 8 + 2;
  781.                 phase_offset_bottom = (7 - hi->selection_phase) * 8 + 2;
  782.             }
  783.             else phase_offset_top = phase_offset_bottom = 8 * 8 + 2;
  784.  
  785.             if ( !left_off ) {
  786.                 PenPat( (ConstPatternParam) ((Ptr)(*marching_ants) + phase_offset_bottom) );
  787.                 MoveTo( pixel_left, t );
  788.                 LineTo( pixel_left, b );
  789.             }
  790.             else pixel_left = col->left;
  791.  
  792.             if ( !right_off ) {
  793.                 PenPat( (ConstPatternParam) ((Ptr)(*marching_ants) + phase_offset_top) );
  794.                 MoveTo( pixel_right, t );
  795.                 LineTo( pixel_right, b );
  796.             }
  797.             else pixel_right = right_pixel_limit;
  798.  
  799.             PenPat( (ConstPatternParam) ((Ptr)(*marching_ants) + phase_offset_top) );
  800.             MoveTo( pixel_left, t );
  801.             LineTo( pixel_right, t );
  802.             PenPat( (ConstPatternParam) ((Ptr)(*marching_ants) + phase_offset_bottom) );
  803.             MoveTo( pixel_left, b );
  804.             LineTo( pixel_right, b );
  805.  
  806.             SetPenState( &save_pen );
  807.         }
  808.     }
  809. }
  810.  
  811.  
  812. column_t *Display_find_column( Heap_info_t *hi, int16 cell_type )
  813. {
  814.     int j;
  815.     column_t *col;
  816.  
  817.     for ( j = hi->row.max_columns, col = &hi->row.column[j]; j >= 0; --j, --col )
  818.         if ( col->cell->type == cell_type ) return col;
  819.  
  820.     assert( false, "\p Display_find_column(): couldn't find column" );
  821. }
  822.  
  823.  
  824. static void add_commas( unsigned char *num )
  825. {
  826.     int16 num_commas, len;
  827.     unsigned char *p;
  828.  
  829.     if ( ( len = *(unsigned char *) num ) < 4 )
  830.         return;
  831.  
  832.     num_commas = (len - 1) / 3;
  833.     *(unsigned char *) num += num_commas;
  834.     p = num + len - 2;
  835.     for ( ; num_commas; --num_commas, p-= 3 ) {
  836.         BlockMove( p, p + num_commas, 3 );
  837.         *(p + num_commas - 1) = ',';
  838.     }
  839. }
  840.  
  841.  
  842. void Check_color_usage( void )
  843. {
  844.     static Boolean checked_once = false;
  845.     Rect window_rect, t_rect;
  846.     int16 min_depth, t_depth, t_index;
  847.     GDHandle gdevice;
  848.     PixMapHandle pmap;
  849.     CTabHandle clut;
  850.     Boolean use_gray;
  851.  
  852.     if ( !This_mac.hasColorQD || color_is_dead )
  853.         Use_color = false;
  854.     else {
  855.         window_rect = App_window->portRect;
  856.         LocalToGlobal( (Point *) &window_rect );
  857.         LocalToGlobal( (Point *) &window_rect.bottom );
  858.         for ( min_depth = 32, use_gray = false, gdevice = GetDeviceList(); gdevice;
  859.                 gdevice = GetNextDevice( gdevice ) ) {
  860.             if ( TestDeviceAttribute( gdevice, screenDevice ) &&
  861.                     TestDeviceAttribute( gdevice, screenActive ) ) {
  862.                 pmap = (**gdevice).gdPMap;
  863.                 if ( SectRect( &(**pmap).bounds, &window_rect, &t_rect ) ) {
  864.                     t_depth = (**pmap).pixelSize;
  865.                     if ( t_depth <= 8 && !TestDeviceAttribute( gdevice, gdDevType ) )
  866.                         use_gray = true;
  867.                     if ( t_depth < min_depth )
  868.                         min_depth = t_depth;
  869.                 }
  870.             }
  871.         }
  872.  
  873.  
  874.         if ( ( Use_color = (min_depth >= MIN_DEPTH_FOR_COLOR) ) ) {
  875. /**
  876.     clut indexes are:
  877.         0    8-bit color
  878.         1    4-bit color
  879.         2    8-bit gray
  880.         3    4-bit gray
  881.  **/
  882.             if ( use_gray )
  883.                 t_index = 2;
  884.             else
  885.                 t_index = 0;
  886.             if ( min_depth == 4 /* 4-bit color */)
  887.                 ++t_index;
  888.         }
  889.         else
  890.             t_index = -1;
  891.  
  892.         if ( checked_once || t_index != clut_index ) {
  893.             if ( !checked_once ) {
  894.                 InvalRect( &App_window->portRect );
  895.                 if ( current_clut )
  896.                     HPurge( (Handle) current_clut );
  897.             }
  898.             clut_index = t_index;
  899.             if ( t_index == -1 )
  900.                 current_clut = NULL;
  901.             else {
  902.                 current_clut = cluts[t_index];
  903.                 if ( !current_clut ) {
  904.                     current_clut = cluts[t_index] =
  905.                             (CTabHandle) GetResource( 'clut', COLOR8_clut + t_index );
  906.                     LoadResource( (Handle) current_clut );    /* make sure we've got it */
  907.                     if ( !current_clut || !*current_clut ) {
  908.                         color_is_dead = true;
  909.                         Use_color = false;
  910.                     }
  911.                     else
  912.                         HNoPurge( (Handle) current_clut );
  913.                 }
  914.             }
  915.         }
  916.     }
  917.     checked_once = true;
  918. }
  919.  
  920.  
  921. void Set_fore_color_or_pattern( int16 color )
  922. {
  923.     if ( Use_color ) {
  924.         HLock( (Handle) current_clut );
  925.         RGBForeColor( &(**current_clut).ctTable[color].rgb );
  926.         HUnlock( (Handle) current_clut );
  927.     }
  928.     else
  929.         PenPat( (ConstPatternParam) ( (Ptr) (*patterns) + color * 8 + 2 ) );
  930. }
  931.  
  932.  
  933. void Set_fore_color( int16 color )
  934. {
  935.     if ( Use_color )
  936.         Set_fore_color_or_pattern( color );
  937. }
  938.  
  939.  
  940. void Set_back_color( int16 color )
  941. {
  942.     if ( Use_color ) {
  943.         HLock( (Handle) current_clut );
  944.         RGBBackColor( &(**current_clut).ctTable[color].rgb );
  945.         HUnlock( (Handle) current_clut );
  946.     }
  947. }
  948.  
  949.  
  950. unsigned char *MBox_text( void )
  951. {
  952.     return mbox_text;
  953. }
  954.  
  955.  
  956. static void draw_mbox( Rect *br )
  957. {
  958.     BitMap bm;
  959.     Handle h;
  960.     Point pen;
  961.     Rect r = *br;
  962.  
  963.     if ( Debugger_installed ) {
  964.         bm.bounds.right = (bm.bounds.left = 3) + 16;
  965.         bm.bounds.top = (bm.bounds.bottom = r.bottom) - 12;
  966.         bm.rowBytes = 2;
  967.         h = GetResource( 'SICN', MACSBUG_SICN );
  968.         HLock( h );
  969.         bm.baseAddr = *h + 8;
  970.         CopyBits( &bm, &App_window->portBits, &bm.bounds, &bm.bounds,
  971.                 srcCopy, NULL );
  972.         HUnlock( h );
  973.     }
  974.  
  975.     MoveTo( 26, r.bottom - 2 );
  976.     //TextMode( srcCopy );
  977.     //TextFont( monaco );
  978.     DrawString( mbox_text );
  979.     //TextMode( srcOr );
  980.     //TextFont( geneva );
  981.     ++r.top;
  982.     GetPen( &pen );
  983.     r.left = pen.h;
  984.     EraseRect( &r );
  985. }
  986.